﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.Media;
using Avalonia.Threading;
using H.Hooks;
using log4net;
using SQLite;
using ui_test.config;
using ui_test.ViewModels;
using Avalonia.Win32;

namespace ui.test.Views;

public partial class UserControl1 : UserControl
{
    private readonly LowLevelKeyboardHook _keyboardHook = new();
    private readonly LowLevelMouseHook _mouseHook = new();

    private static readonly ILog log = LogManager.GetLogger(typeof(UserControl1));

    public UserControl1()
    {
        var model = new UserControl1ViewModel();
        DataContext = model;
        InitializeComponent();
        try
        {
            InitDataBase();
            AddHooks();
        }
        catch (Exception e)
        {
            log.Error(e);
        }
    }

    private static void InitDataBase()
    {
        var columnInfos = ConnectManager.Connection.GetTableInfo("key_record");
        if (columnInfos == null || columnInfos.Count == 0)
        {
            var createTableResult = ConnectManager.Connection.CreateTable<KeyRecord>();
            log.Info($"create table result -> {createTableResult == CreateTableResult.Created}");
        }
    }

    private void AddHooks()
    {
        var model = (DataContext as UserControl1ViewModel);
        _keyboardHook.Down += (((_, args) =>
        {
            ChangeBackground(model.KeyMapInFirstLine, args: args);
            ChangeBackground(model.KeyMapInSecLine, args: args);
            ChangeBackground(model.KeyMapIn3thLine, args: args);
            ChangeBackground(model.KeyMapIn4thLine, args: args);
            ChangeBackground(model.KeyMapIn5thLine, args: args);
            ChangeBackground(model.KeyMapIn6thLine, args: args);
        }));
        _keyboardHook.Up += ((_, args) =>
        {
            RecoverBackground(model.KeyMapInFirstLine, args);
            RecoverBackground(model.KeyMapInSecLine, args);
            RecoverBackground(model.KeyMapIn3thLine, args);
            RecoverBackground(model.KeyMapIn4thLine, args);
            RecoverBackground(model.KeyMapIn5thLine, args);
            RecoverBackground(model.KeyMapIn6thLine, args);
            Console.WriteLine(args.CurrentKey);
            DoRecord(model, args, keyType: KeyRecord.KeyTypeEnum.Keyboard);
        });
        _keyboardHook.Start();
        _mouseHook.Down += (_, args) =>
        {
            var currentKey = args.CurrentKey;
            if (currentKey.Equals(Key.MouseLeft))
            {
                Dispatcher.UIThread.InvokeAsync((() => LeftBorder.Background = Brushes.Yellow));
            }

            if (currentKey.Equals(Key.MouseRight))
            {
                Dispatcher.UIThread.InvokeAsync((() => RightBorder.Background = Brushes.Yellow));
            }
        };
        _mouseHook.Up += (_, args) =>
        {
            var currentKey = args.CurrentKey;
            if (currentKey.Equals(Key.MouseLeft))
            {
                Dispatcher.UIThread.InvokeAsync((() => LeftBorder.Background = Brushes.Crimson));
            }

            if (currentKey.Equals(Key.MouseRight))
            {
                Dispatcher.UIThread.InvokeAsync((() => RightBorder.Background = Brushes.Crimson));
            }

            DoRecord(model, args, keyType: KeyRecord.KeyTypeEnum.Mouse);
        };
        _mouseHook.Wheel += (_, args) =>
        {
            Dispatcher.UIThread.InvokeAsync((() => MiddleBorder.Background = Brushes.Yellow));
            DoRecord(model, args, keyType: KeyRecord.KeyTypeEnum.MouseWheel);
            Dispatcher.UIThread.InvokeAsync((() => MiddleBorder.Background = Brushes.Fuchsia));
        };
        _mouseHook.Move += (_, args) => { Console.WriteLine($"{args.Position}"); };
        _mouseHook.Start();
    }

    private static readonly object _readWriteLock = new();
    private static Semaphore semaphore = new(1, 1);

    private static void DoRecord(UserControl1ViewModel model, KeyboardEventArgs args, KeyRecord.KeyTypeEnum keyType)
    {
        DoKeyboardInc(model, args, keyType);

        // lock (_readWriteLock)
        // {
        semaphore.WaitOne();
        try
        {
            var keyRecords = ConnectManager.Connection
                .Query<KeyRecord>($"select * from key_record where  name =  '{args.CurrentKey.ToString()}'");
            if (keyRecords!=null && keyRecords.Count > 1)
            {
               Console.WriteLine(999999999999); 
            }
            var hasRecord = !(keyRecords == null || keyRecords.Count == 0);
            Console.WriteLine($"current key is {args.CurrentKey} hasRecord = {hasRecord}");

            if (!hasRecord)
            {
                ConnectManager.Connection.Insert(new KeyRecord()
                {
                    Name = args.CurrentKey.ToString(),
                    Times = 1,
                    KeyType = keyType.ToString(),
                    UpdateTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")
                });
            }
            else
            {
                var keyRecord = keyRecords.First();
                ConnectManager.Connection.Execute(
                    @$"update key_record set times = {keyRecord.Times + 1} where id = {keyRecord.Id}");
                // ConnectManager.Connection.Update(new KeyRecord()
                // {
                //     Id = keyRecord.Id,
                //     Name = keyRecord.Name,
                //     KeyType = keyType.ToString(),
                //     Times = keyRecord.Times + 1,
                //     UpdateTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")
                // });
            }
        }
        finally
        {
            semaphore.Release();
        }
    }

    private static void DoKeyboardInc(UserControl1ViewModel model, KeyboardEventArgs args,
        KeyRecord.KeyTypeEnum keyType)
    {
        switch (keyType)
        {
            case KeyRecord.KeyTypeEnum.Keyboard:
                DoInc(model.KeyMapInFirstLine, args);
                DoInc(model.KeyMapInSecLine, args);
                DoInc(model.KeyMapIn3thLine, args);
                DoInc(model.KeyMapIn4thLine, args);
                DoInc(model.KeyMapIn5thLine, args);
                DoInc(model.KeyMapIn6thLine, args);
                break;
            case KeyRecord.KeyTypeEnum.Mouse:
                switch (args.CurrentKey)
                {
                    case Key.MouseLeft:
                        Dispatcher.UIThread.InvokeAsync((() => { model.LeftClickCount++; }));
                        break;
                    case Key.MouseRight:
                        Dispatcher.UIThread.InvokeAsync((() => { model.RightClickCount++; }));
                        break;
                }

                break;
            case KeyRecord.KeyTypeEnum.MouseWheel:
                Dispatcher.UIThread.InvokeAsync((() => { model.WheelClickCount++; }));
                break;
        }
    }

    private static void DoInc(Dictionary<string, KeyUserControl> map, KeyboardEventArgs args)
    {
        if (map.ContainsKey(args.CurrentKey.ToString()))
        {
            var userControl = map[args.CurrentKey.ToString()];
            Dispatcher.UIThread.InvokeAsync((() => { userControl.CountText++; }));
        }
    }

    private static readonly object _lockObjectOfChangeBackground = new();
    private static readonly object _lockObjectOfRecoverBackground = new();

    private static void ChangeBackground(Dictionary<string, KeyUserControl> map, KeyboardEventArgs args)
    {
        if (map.ContainsKey(args.CurrentKey.ToString()))
        {
            var userControl = map[args.CurrentKey.ToString()];
            Dispatcher.UIThread.InvokeAsync((() =>
            {
                lock (_lockObjectOfChangeBackground)
                {
                    userControl.Backup = userControl.BackgroundColor;
                    userControl.BackgroundColor = Brushes.Yellow;
                }
            }));
        }
    }

    private static void RecoverBackground(Dictionary<string, KeyUserControl> map, KeyboardEventArgs args)
    {
        if (map.ContainsKey(args.CurrentKey.ToString()))
        {
            var userControl = map[args.CurrentKey.ToString()];

            Dispatcher.UIThread.InvokeAsync((() =>
            {
                lock (_lockObjectOfRecoverBackground)
                {
                    userControl.BackgroundColor = userControl.Backup;
                    userControl.Backup = null;
                }
            }));
        }
    }

    public override void BeginInit()
    {
        base.BeginInit();
        Console.WriteLine("begin init...");
    }

    public override void EndInit()
    {
        base.EndInit();
        Console.WriteLine("end init...");
    }

    protected override void OnLoaded(RoutedEventArgs e)
    {
        base.OnLoaded(e);
        Console.WriteLine("loaded ...");
        ShowData();
    }

    private void ShowData()
    {
        var model = DataContext as UserControl1ViewModel;
        var keyRecords = ConnectManager.Connection.Query<KeyRecord>("select * from key_record");
        if (keyRecords != null && keyRecords.Count > 0)
        {
            foreach (var record in keyRecords)
            {
                DoShow(model.KeyMapInFirstLine, record);
                DoShow(model.KeyMapInSecLine, record);
                DoShow(model.KeyMapIn3thLine, record);
                DoShow(model.KeyMapIn4thLine, record);
                DoShow(model.KeyMapIn5thLine, record);
                DoShow(model.KeyMapIn6thLine, record);
                if (record.Name.Equals(Key.MouseLeft.ToString()))
                {
                    model.LeftClickCount = record.Times;
                }

                if (record.Name.Equals(Key.MouseRight.ToString()))
                {
                    model.RightClickCount = record.Times;
                }

                if (record.Name.Equals(Key.MouseWheel.ToString()))
                {
                    model.WheelClickCount = record.Times;
                }
            }
        }
    }

    private void DoShow(Dictionary<string, KeyUserControl> map, KeyRecord record)
    {
        if (map.TryGetValue(record.Name, out var userControl1))
        {
            Dispatcher.UIThread.InvokeAsync((() => { userControl1.CountText = record.Times; }));
        }
    }

    protected override void OnUnloaded(RoutedEventArgs e)
    {
        base.OnUnloaded(e);
        Console.WriteLine("unloaded ...");
    }
}